package com.gitee.wsl.mathematics.matrix.ext

import com.gitee.wsl.mathematics.matrix.Matrix
import com.gitee.wsl.mathematics.vector.Vector


class Coordinate(
    var father: Coordinate?, //路径
    var x: Int, //深度
    var y: Int,
    val coordinateList: ArrayList<Coordinate> = ArrayList(),
)

fun Coordinate?.isDo(i:Int, j:Int):Boolean = if(this==null) false else coordinateList.find { it.x == i && it.y ==j } != null

fun Coordinate.isNext(i: Int, isOk: Boolean): Boolean {
    var isOk = isOk
    //if (coordinate == null) { //此路可走
    //    return true
    //}
    if (isOk) {
        if (x != i && father!=null ) {
            isOk = father!!.isNext(i, true)
        } else { //此路不通
            return false
        }
    }
    return isOk
}

fun inverseNumber(myInverse: FloatArray): Int { //逆序数奇偶性判定
    val size = myInverse.size
    var inverserNumber = 0
    for (i in 0 until size) {
        val element = myInverse[i]
        for (j in (i + 1) until size) {
            if (myInverse[j] < element) {
                inverserNumber++
            }
        }
    }
    return inverserNumber
}

private fun parity(list: List<Coordinate>): Boolean { //获取排列奇偶性
    var parity = true //默认是偶排列
    val row = FloatArray(list.size)
    val clo = FloatArray(list.size)
    for (i in list.indices) {
        row[i] = (list[i].x + 1).toFloat()
        clo[i] = (list[i].y + 1).toFloat()
    }
    val rowInv = inverseNumber(row)
    val cloInv = inverseNumber(clo)
    val inverserNumber = rowInv + cloInv
    if (inverserNumber % 2 != 0) { //奇排列
        parity = false
    }
    return parity
}

class CoordinateCalc<T:Number,V:Matrix<T,V,R>,R: Vector<T, R>>(val matrix: Matrix<T,V,R>){
    private val coordinateRoot: MutableList<Coordinate>? = null
    private var defNub = 0f //行列式计算结果

    @Throws(Exception::class)
    private fun mulFather(
        coordinate: Coordinate?,
        element: Float,
        div: MutableList<Coordinate>,
    ): Float {
        var element = element
        coordinate?.let {
            div.add(it)
            element *= matrix.get(coordinate.x, coordinate.y).toFloat()
        }
        if (coordinate?.father != null) {
            element = mulFather(coordinate.father, element, div)
        } else { //道路尽头
            defNub = if (parity(div)) { //偶排列
                defNub + element
            } else { //奇排列
                defNub - element
            }
            div.clear()
            element = 1f
        }
        return element
    }

    private fun isNext(coordinate: Coordinate?,i: Int, isOk: Boolean): Boolean {
        coordinate?:return true
        return coordinate.isNext( i, isOk)
    }


    private fun findRout(coordinate: Coordinate?, j: Int, initi: Int, isDown: Boolean): Boolean {
        var j = j
        var isDown = isDown
        for (i in 0 until matrix.rowCount) { //层数
            if (!isDown) {
                break
            }
            var row = i
            if (coordinate == null) {
                row = initi
            }
            val isOk = isNext(coordinate, row, true) && !coordinate.isDo(row, j)
            if (isOk) {
                val coordinateNext = Coordinate(coordinate, row, j)
                coordinate?.coordinateList?.add(coordinateNext) ?: coordinateRoot?.add(coordinateNext)

                if (coordinateNext.y < (matrix.colCount - 1)) { //深入
                    j++
                    isDown = findRout(coordinateNext, j, initi, isDown)
                } else if (coordinate != null && coordinateNext.y > 1 && coordinateNext.x == (matrix.rowCount - 1)) {
                    //缩头
                    j--
                    isDown = findRout(coordinate.father, j, initi, isDown)
                } else if (coordinateNext.y == 1) {
                    isDown = false
                    break
                }
            } else {
                if (i == (matrix.rowCount - 1) && j > 1) { //行已经到极限了 缩头
                    j--
                    isDown = findRout(coordinate!!.father, j, initi, isDown)
                } else if (j == 1 && i == (matrix.rowCount - 1)) { //跳出
                    isDown = false
                    break
                }
            }
        }

        return isDown
    }
}